﻿using SimpleTerminal.Common;
using System;
using System.IO;
using System.IO.Ports;
using System.Text;

namespace SimpleTerminal.Session
{
    class SerialConnection : IConnection
    {
        readonly SerialPort serialPort;
        protected bool isConnected = false;
        protected string portName;

        public SerialConnection(string portName, int baudRate, int dateBits, string parity, string stopBits)
        {
            serialPort = new SerialPort
            {
                PortName = portName,
                BaudRate = baudRate,
                DataBits = dateBits
            };


            if (parity.Equals("None"))
                serialPort.Parity = Parity.None;
            else if (parity.Equals("Odd"))
                serialPort.Parity = Parity.Odd;
            else if (parity.Equals("Even"))
                serialPort.Parity = Parity.Even;
            else if (parity.Equals("Mark"))
                serialPort.Parity = Parity.Mark;
            else if (parity.Equals("Space"))
                serialPort.Parity = Parity.Space;

            if (stopBits.Equals("1"))
                serialPort.StopBits = StopBits.One;
            else if (stopBits.Equals("1.5"))
                serialPort.StopBits = StopBits.OnePointFive;
            else if (stopBits.Equals("2"))
                serialPort.StopBits = StopBits.Two;

            serialPort.PinChanged += new SerialPinChangedEventHandler(PinChanged);
        }

        protected void PinChanged(object sender, SerialPinChangedEventArgs e)
        {
            // Log.Debug("Serial", e.EventType.ToString());
            //e.EventType = SerialPinChange.
        }


        public override void Connect()
        {
            serialPort.ErrorReceived += OnErrorReceivedEventHandler;
            serialPort.DataReceived += OnDataReceivedEventHandler;
            OnConnecting(serialPort.PortName);
            try
            {
                serialPort.Open();
                Connected?.Invoke(this);
            }
            catch (UnauthorizedAccessException)
            {
                OnError(Errors.CONNECT_ERROR, "串口无法访问，可能已被占用或者已打开");
                serialPort.DataReceived -= OnDataReceivedEventHandler;

            }
            catch (IOException ioe)
            {
                OnError(Errors.CONNECT_ERROR, ioe.Message);
                serialPort.DataReceived -= OnDataReceivedEventHandler;

            }
            finally
            {
            }
        }

        public void OnErrorReceivedEventHandler(object sender, SerialErrorReceivedEventArgs e)
        {
            //e.EventType = SerialError.
        }

        public void OnDataReceivedEventHandler(object sender, SerialDataReceivedEventArgs e)
        {
            //int size = serialPort.ReceivedBytesThreshold;
            int size = serialPort.BytesToRead;
            byte[] bytes = new byte[size];
            int bytesToRead = 0;
            do
            {
                bytesToRead += serialPort.Read(bytes, bytesToRead, size - bytesToRead);
            } while (bytesToRead < size);

            DataReceived?.Invoke(this, new DataEventArgs { Data = bytes });

            //DataReceived?.Invoke(this, new DataEventArgs { Data = Encoding.ASCII.GetBytes(serialPort.ReadExisting()) });
        }

        public override void SendKeepAlive()
        {
            base.SendKeepAlive();
            if (serialPort.IsOpen)
            {
                Log.Debug("Serial SendKeepAlive", "open");
            }
            else
            {
                Log.Debug("Serial SendKeepAlive", "close");
            }
        }

        public override void Disconnect()
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close();
            }
            Dispose(true);
            OnDisconnected();
        }

        public override void Send(string text)
        {
            if (serialPort.IsOpen && Canwrite)
            {
                serialPort.Write(text);
            }
        }

        public override SessionType GetSessionType()
        {
            return SessionType.Serial;
        }




        protected override void Dispose(bool disposing)
        {
            if (_isDisposed)
                return;

            if (disposing)
            {
                if (isConnected)
                    Disconnect();
                serialPort.Dispose();
            }
            _isDisposed = true;
        }

        public override bool IsConnected()
        {
            return serialPort.IsOpen;
        }
    }
}
